import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Point2D;


public class PhysicsMethods{

//	Rectangle r2 = new Rectangle(230, 190, 30, 30);
//	Point p1 = new Point(210,180);
//	Point p3 = new Point(120,300);
//
//	Point vvec = new Point(140,-10);
	
	
	Rectangle r2;
	Point p1;
	Point p3;
	Point vvec; //velocity vector
	
	
	
	


	//This draw method demonstrates how to actually use the calcstuff meethod...
	//maybe rename calcstuff to something bettah?
	
//	public void paint(Graphics g){
//
//		Graphics2D g2 = (Graphics2D)g;
//		
//		//Get collision results
//		double[] results = collisionStuff( r2, p1, p3, vvec);
//
//		//System.out.println(Arrays.toString(results));
//
//		r2.x += results[0];
//		r2.y += results[1];
//
//		//if a collision took place
//		if(results[4]==1){
//
//			//In the real use of this code, don't cast or round.
//			//The player class will take movement and velocity of the player as Double's
//			//and then deal with rounding and stuff when drawing the player
//			//rectangle.
//			
//			//REMEMBER that the d(x) and d(y) returned are in pixels, and 
//			// the velocity changes are in METERS (whatever is passed in, which happens
//			// to be meters) so convert stuff if needed.
//			
//			
//			//here, however, we dont have that luxury so we just cast for
//			//sake of simplicity
//			vvec.x = (int) results[2];
//			vvec.y = (int) results[3];
//		}
//
//		//random screen clearing ftw
//		g2.clearRect(0,0,1000, 1000);
//
//		g2.setColor(Color.DARK_GRAY);
//		g2.draw(r2);
//
//		g2.setColor(Color.green);
////		drawLine(g2, r2.getCenterX(), r2.getCenterY(), r2.getCenterX() + vvec.x, r2.getCenterY()+ vvec.y);
//
//		g2.setColor(Color.red);
//		g2.drawLine(p1.x, p1.y, p3.x, p3.y);
//
//	}


	//Return [d(x), d(y), new vx, new vy, [1:if collision occurred, 0 if no collision occurred]]
	//i.e. the displacement of the rectangle, and the new velocities.
	public static double[] collisionStuff(Rectangle r2, Point p1, Point p3, Point2D.Double vvec){
		

		Point p2 = findPoint2(p1.x, p1.y, p3.x, p3.y, (int)r2.getCenterX(), (int)r2.getCenterY());




		Point n1vec = new Point((p3.y - p1.y),p1.x - p3.x); //Normal vector

		double proj_a = (n1vec.x*(p2.x - p1.x) + n1vec.y*(p2.y-p1.y))/n1vec.distance(0,0);  //generalized projection for p2 = angle opposite hypot


		//System.out.println("proja:"+proj_a);

		//draw the projection


		Point p1cr_vec = new Point((int)r2.getCenterX()-p1.x, (int)r2.getCenterY() - p1.y);

		double rproj = project(p1cr_vec,n1vec);
		//System.out.println("ref:"+rproj);

		//Project the p1-center vector onto N1 to find the center of the shape...
		double s_radius = Math.abs(project(new Point(0,r2.height/2),n1vec)) + Math.abs(project(new Point(r2.width/2,0),n1vec));
		//System.out.println("rec1/2shadow:"+s_radius);

		//If overlap is detected
		if(		overlap( p1.y, p3.y, r2.getMinY(), r2.getMaxY()) &&
				overlap( p3.x,p1.x,r2.getMinX(),r2.getMaxX())&& 
				overlap(rproj-s_radius,rproj+s_radius,0,proj_a)	){//then...

			//now that we know a collision takes place, we don't feel bad about about allocationg double arrays...
			int dispindex=-1;
			double [] dispvec = new double[]{
					overlap2(0, proj_a,rproj-s_radius, rproj+s_radius),
					overlap2( p3.x, p1.x, r2.getMinX(), r2.getMaxX() ),
					overlap2( p1.y, p3.y, r2.getMinY(), r2.getMaxY())};



			double[] mdv=new double[]{Math.abs(dispvec[0]), Math.abs(dispvec[1]), Math.abs(dispvec[2])};
			if(mdv[0]< mdv[1]){
				dispindex = (mdv[0]< mdv[2])? 0:2;
			}else{
				dispindex = (mdv[1]< mdv[2])? 1:2;
			}

			//TODO: only calculate this if the dispind shows the reflection was hypotenal? horiz and vert. imapacts just reflect over xyaxis
			//Calculate resulting velocity vector from incident velocity vector
			// I' = I - 2*dot(I,Nhat)*Nhat
			//aka I' = I - 2 proj(I onto Nhat)*nhat
			
			
			
			double P = project(vvec.x, vvec.y, n1vec.x, n1vec.y);///n1vec.distance(0, 0);
			
			
			Point2D.Double I = new Point2D.Double(
					(vvec.x - 2* P* n1vec.x/n1vec.distance(0, 0)),
					(vvec.y - 2* P* n1vec.y/n1vec.distance(0, 0))
			);		
			
			if(dispindex == 0){
				//calc theta now that we have a use for it...
				double theta = Math.atan2( n1vec.y, n1vec.x);
				return new double[]{dispvec[0]*Math.cos(theta), dispvec[0]*Math.sin(theta), I.x /*dvx*/,I.y  /*dvy*/ , 1};
			}else if (dispindex == 1){
				return new double[]{dispvec[1],0, I.x /*v'x*/,I.y  /*v'y*/ , 1};
			}else if (dispindex == 2){
				return new double[]{0, dispvec[2], I.x /*v'x*/,I.y  /*v'y*/, 1 };
			}

		}

		//no collision so no change in anythingness....
		//System.out.println("null 0'd"); // <--- wth does this mean again? xP
		return new double[]{0,0,0,0,0};

	}



	//Does an overlap exist?
	public static boolean overlap(double a1, double a2, double b1, double b2){

		double r_ep = Math.max(Math.max(a1,a2),Math.max(b1,b2));
		double l_ep = Math.min(Math.min(a1,a2),Math.min(b1,b2));

		double overlap = Math.abs(r_ep - l_ep) - Math.abs( a2-a1) - Math.abs(b2-b1);

		if(overlap < 0) return true;
		return false;

	}
	
	//Find point 2 based on points 1 and 3... (hypotenal points)
	public static Point findPoint2(int ax,int ay,int bx,int by,int qx,int qy){
		Point pt = new Point();
		//bx should always be the right-most point.
		if(bx < ax){
			//swap p3 and p1...
			//System.out.println("swapperz");
			int tx = ax, ty = ay;
			ax = bx; ay = by;
			bx = tx; by = ty;
		}

		double slope = (double)(by-ay)/ (double)(bx-ax);

		if( qy - ay > slope*( qx - ax)){ //above
			pt.y = Math.min(ay, by);

			if( slope>=0){
				pt.x = bx;				
			}else{
				pt.x = ax;

			}
		}else{
			pt.y = Math.max(ay,by);

			if(slope >=0){
				pt.x = ax;
			}else{
				pt.x = bx;
			}
		}

		return pt;

		//TODO: Watch for the case where a and b are points that are right above one-another (divide by 0 error in the slope).

	}

	//Determines the displacement for the movable-object (namely, the second one)
	//The immovable object's projection needs to be specified first!!!!!! (as a1,a2)
	public static double overlap2(double a1, double a2, double b1, double b2){

		if(a1>a2){
			double t = a1;
			a1 = a2;
			a2 = t;			
		}
		if(b1>b2){
			double t = b1;
			b1 = b2;
			b2 = t;			
		}

		if(  Math.abs(a1-b2) > Math.abs(a2-b1)) //displace to the right
			return Math.abs(a2-b1);
		//otherwise:
		return -Math.abs(a1-b2);

	}


	//Vector projection (v1 onto v2)
	public static double project(Point v1,/*onto*/ Point v2){
		double a = v1.x*v2.x + v1.y*v2.y;
		return a/v2.distance(0, 0);
	}
	public static double project(double v1x, double v1y, /*onto*/ double v2x, double v2y){
		double a = v1x*v2x + v1y*v2y;
		return a/Math.sqrt( v1x*v1x + v1y*v1y  );
	}
	
	

//	public void drawLine(Graphics2D g2, double x, double y, double x1, double y1){
//		g2.drawLine( (int)Math.round(x), (int)Math.round(y), (int)Math.round(x1), (int)Math.round(y1));
//	}





//	public static void main(String[]args){
//		new nphys_method();		
//	}
//	public void mouseDragged(MouseEvent arg0) {
//	}
//	public void mouseMoved(MouseEvent arg0) {
//		r2.setLocation((int)(arg0.getPoint().x - r2.getWidth()/2.0),(int)( arg0.getPoint().y - r2.getHeight()/2.0));
//	}
		
	
//	public nphys_method(){
//		setTitle("N-PhysTutorial test");
//		setSize(400,600);
//		setVisible(true);
//		setDefaultCloseOperation(EXIT_ON_CLOSE);
//
//		(new Timer(10, new ActionListener() {
//			public void actionPerformed(ActionEvent e) {
//				repaint();				
//			}
//		})).start();
//		this.addMouseMotionListener(this);
//
//	}
}
